package xcmg.device.service.warehouse;

import com.github.pagehelper.PageInfo;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import xcmg.device.dao.entity.barcode.BarcodeManageDO;
import xcmg.device.dao.entity.company.CompanySupplierDO;
import xcmg.device.dao.entity.warehouse.DeliveryInstructionDO;
import xcmg.device.dao.entity.warehouse.DeliveryInstructionDetailDO;
import xcmg.device.dao.entity.warehouse.DeliveryInstructionPostingDO;
import xcmg.device.dao.entity.warehouse.WarehouseInboundDO;
import xcmg.device.dao.entity.warehouse.WarehouseInboundDetailDO;
import xcmg.device.dao.entity.warehouse.WarehouseInboundRecordDO;
import xcmg.device.dao.mapper.BarcodeManageMapper;
import xcmg.device.dao.mapper.CompanySupplierMapper;
import xcmg.device.dao.mapper.warehouse.DeliveryInstructionDetailMapper;
import xcmg.device.dao.mapper.warehouse.DeliveryInstructionMapper;
import xcmg.device.dao.mapper.warehouse.DeliveryInstructionPostingMapper;
import xcmg.device.dao.mapper.warehouse.WarehouseAreaLocationDOMapper;
import xcmg.device.dao.mapper.warehouse.WarehouseInboundDetailMapper;
import xcmg.device.dao.mapper.warehouse.WarehouseInboundMapper;
import xcmg.device.dao.mapper.warehouse.WarehouseInboundRecordMapper;
import xcmg.device.dao.mapper.warehouse.WarehouseInventoryMapper;
import xcmg.device.infra.DateUtil;
import xcmg.device.infra.ErrorCode;
import xcmg.device.infra.ExportUtil;
import xcmg.device.infra.enums.BillDesc;
import xcmg.device.infra.enums.InboundStatusEnum;
import xcmg.device.infra.enums.PostingStatusEnum;
import xcmg.device.infra.enums.SapSynStatusEnum;
import xcmg.device.service.GenDocumentService;
import xcmg.device.service.company.CompanyInfoService;

import xcmg.device.service.vo.company.CompanyInfoVO;
import xcmg.device.service.vo.warehouse.DeliveryInstructionAddVO;
import xcmg.device.service.vo.warehouse.DeliveryInstructionDetailVO;
import xcmg.device.service.vo.warehouse.DeliveryInstructionItemVO;
import xcmg.device.service.vo.warehouse.DeliveryInstructionVO;
import xcmg.device.service.vo.warehouse.WarehouseInboundRecordVO;
import yb.ecp.fast.feign.FastGenClient;
import yb.ecp.fast.infra.infra.ActionResult;
import yb.ecp.fast.infra.infra.PageCommonVO;
import yb.ecp.fast.infra.infra.SearchCommonVO;
import yb.ecp.fast.infra.infra.log.LogHelper;
import yb.ecp.fast.infra.util.ListUtil;
import yb.ecp.fast.infra.util.PageHelperPlus;
import yb.ecp.fast.infra.util.StringUtil;

import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

@Service
public class DeliveryInstructionService {

    @Autowired
    private DeliveryInstructionMapper deliveryInstructionMapper;

    @Autowired
    private DeliveryInstructionDetailMapper deliveryInstructionDetailMapper;

    @Autowired
    private DeliveryInstructionDetailService deliveryInstructionDetailService;

    @Autowired
    private GenDocumentService genDocumentService;

    @Autowired
    private FastGenClient fastGenClient;

    @Autowired
    private HttpServletResponse response;

    @Autowired
    private WarehouseInboundService warehouseInboundService;

    @Autowired
    private CommonService commonService;

    @Autowired
    private CompanyInfoService companyInfoService;

    @Autowired
    private CompanySupplierMapper companySupplierMapper;

    @Autowired
    private DeliveryInstructionPostingMapper deliveryInstructionPostingMapper;

    @Autowired
    private WarehouseInboundDetailMapper warehouseInboundDetailMapper;

    @Autowired
    private WarehouseInboundRecordMapper warehouseInboundRecordMapper;

    @Autowired
    private BarcodeManageMapper barcodeManageMapper;

    @Autowired
    private WarehouseInventoryMapper warehouseInventoryMapper;

    @Autowired
    private WarehouseInboundMapper warehouseInboundMapper;
    @Autowired
    private WarehouseAreaLocationDOMapper warehouseAreaLocationDOMapper;

    //收货零件凭证
    private static final String IN_VOUCHER_CODE = "MBLNR1";
    //发货零件凭证
    private static final String OUT_VOUCHER_CODE = "MBLNR2";


    /**
     * @Author: WangKe
     * @Description: 生成配送指令入库单记录
     * @Date: 2018/4/17 0017
     */
    @Transactional(rollbackFor = Exception.class)
    public ErrorCode add(DeliveryInstructionAddVO deliveryInstructionAddVO, String userId, String orgId) throws Exception {
        CompanyInfoVO companyInfoVO = companyInfoService.info(orgId);
        //判断当前企业是否调用sap接口
        if (companyInfoVO == null || companyInfoVO.getIsSap() == null || companyInfoVO.getIsSap() == 0) {
            throw new Exception("当前企业不可调用SAP接口");
        }
//        List<Map<String, String>> dataList = sapCommonService.getDeliveryInstructionFromSAP(deliveryInstructionAddVO, companyInfoVO.getSapCode());
//        if(ListUtil.isNullOrEmpty(dataList)){
//            return ErrorCode.IllegalArument;
//        }
//        //判断是否需要生成主表记录
//        boolean success;
//        boolean allIn = false;
//        DeliveryInstructionDO deliveryInstructionDO = deliveryInstructionMapper.selectByDeliveryInstruction(deliveryInstructionAddVO.getDeliveryInstructionNo(), orgId);
//        if(deliveryInstructionDO == null){
//            allIn = true;
//            deliveryInstructionDO = this.insert(deliveryInstructionAddVO, dataList.get(0), companyInfoVO.getSapCode(), userId, orgId);
//            if(deliveryInstructionDO == null){
//                return ErrorCode.Failure;
//            }
//        }
//        //新增配送指令入库详情记录
//        List<DeliveryInstructionDetailDO> detailDOList = deliveryInstructionDetailService.add(deliveryInstructionDO, dataList, userId, orgId);
//
//        //生成入库主记录和入库详情记录
//        if(allIn){
//            success = warehouseInboundService.saveByDeliveryInstruction(deliveryInstructionDO, detailDOList, userId, orgId);
//            if(!success){
//                throw new Exception("生成入库主记录和入库详情记录出错");
//            }
//        }else{
//            success = deliveryInstructionDetailService.addInboundDetail(detailDOList, orgId);
//            if(!success){
//                throw new Exception("生成入库详情记录出错");
//            }
//        }

        return ErrorCode.Success;
    }

    /**
     * @Author: WangKe
     * @Description: 新增配送指令主表记录
     * @Date: 2018/4/17 0017
     */
    @Transactional(rollbackFor = Exception.class)
    public DeliveryInstructionDO insert(DeliveryInstructionAddVO deliveryInstructionAddVO, Map<String, String> map, String werks, String userId, String orgId)throws Exception{
        ActionResult<String> textResult = fastGenClient.textGuid();
        if (textResult.getCode() != ErrorCode.Success.getCode())
        {
            return null;
        }
        DeliveryInstructionDO deliveryInstructionDO = new DeliveryInstructionDO();
        deliveryInstructionDO.setDeliveryInstructionNo(deliveryInstructionAddVO.getDeliveryInstructionNo());
        deliveryInstructionDO.setWarehouseCode(deliveryInstructionAddVO.getWarehouseCode());
        deliveryInstructionDO.setDept(deliveryInstructionAddVO.getDept());
        deliveryInstructionDO.setDeptId(deliveryInstructionAddVO.getDeptId());
        deliveryInstructionDO.setWerks(werks);
        deliveryInstructionDO.setOrgId(orgId);

        CompanySupplierDO supplierDO = companySupplierMapper.itemByCode(orgId, map.get("LIFNR"));
        if(supplierDO == null){
            throw new Exception("未能根据返回的供应商编码找到供应商，"+map.get("LIFNR"));
        }
        if(!StringUtil.isNullOrEmpty(supplierDO.getPlatOrgId())){
            deliveryInstructionDO.setSupplierOrgId(supplierDO.getPlatOrgId());
        }else{
            deliveryInstructionDO.setSupplierOrgId(supplierDO.getSupplierOrgId());
        }
        deliveryInstructionDO.setSupplierName(supplierDO.getCompanyName());
        deliveryInstructionDO.setVoucherNo(map.get("EBELN"));
        deliveryInstructionDO.setVoucherProNo(map.get("EBELP"));

        deliveryInstructionDO.setId(textResult.getValue());
        deliveryInstructionDO.setDeliveryOrder(genDocumentService.getDocumentNo(BillDesc.DeliveryInstruction));
        deliveryInstructionDO.setState(0);
        deliveryInstructionDO.setCreateId(userId);
        deliveryInstructionDO.setCreateName(commonService.getUserName(userId));
        deliveryInstructionDO.setCreateDate(new Date());

        return deliveryInstructionMapper.insert(deliveryInstructionDO)>0?deliveryInstructionDO:null;
    }

    private BigDecimal getHasPostedQty(String detailId) {
        BigDecimal hasPostedQty = deliveryInstructionPostingMapper.getPostedQty(detailId);
        return null == hasPostedQty ? BigDecimal.ZERO : hasPostedQty;
    }

    /**
     * @Author: WangKe
     * @Description: 配送指令过账
     * @Date: 2018/4/17 0017
     */
//    @Transactional(rollbackFor = Exception.class)
//    public ErrorCode doPosting(String detailId, String userId) throws Exception {
//        DeliveryInstructionDetailDO detailDO = deliveryInstructionDetailMapper.selectByPrimaryKey(detailId);
//        if (null == detailDO) {
//            LogHelper.error("detailDO is null.detailId:" + detailId + ", userId:" + userId, ErrorCode.IllegalArument.getCode());
//            throw new Exception("参数错误，未查询到该条配送指令入库的零件");
//        }
//        DeliveryInstructionDO deliveryInstructionDO = deliveryInstructionMapper.selectByDeliveryOrder(detailDO.getDeliveryOrder(), detailDO.getOrgId());
//        if (null == deliveryInstructionDO) {
//            LogHelper.error("deliveryInstructionDO is null.deliveryOrder:" + detailDO.getDeliveryOrder() + ",orgOd:" + detailDO.getOrgId(), ErrorCode.IllegalArument.getCode());
//            throw new Exception("参数错误，未查询到配送指令入库信息");
//        }
//        if (detailDO.getRealAmount().compareTo(BigDecimal.ZERO) == 0) {
//            throw new Exception("此零件尚未入库，不能过账");
//        }
//        // 已过账的数量
//        BigDecimal hasPostedQty = getHasPostedQty(detailId);
//        // 本次过账数量
//        BigDecimal postQty = detailDO.getRealAmount().subtract(hasPostedQty);
//
//        OutputParam outputParam = sapCommonService.deliveryInstructionPosting(detailDO, deliveryInstructionDO.getSapInArea(), postQty);
//        Map<String, String> map = outputParam.getDataList().get(0);
//        if (!"S".equals(map.get(RETURN_CODE))) {
//            SappostErrorRecordDO sappostErrorRecordDO=new SappostErrorRecordDO();
//            sappostErrorRecordDO.setBusinessNo(detailDO.getDeliveryInstructionNo());
//            sappostErrorRecordDO.setMaterialNo(detailDO.getMaterialNo());
//            sappostErrorRecordDO.setRowNo(detailDO.getRowNo());
//            sappostErrorRecordDO.setOrgId(detailDO.getOrgId());
//            sappostErrorRecordDO.setErrorMessage(map.get(RETURN_MESSAGE));
//            sappostErrorRecordDO.setOrderCreateId(deliveryInstructionDO.getCreateId());
//            sappostErrorRecordDO.setOrderCreateName(deliveryInstructionDO.getCreateName());
//            sappostErrorRecordDO.setSapOrderNo(deliveryInstructionDO.getDeliveryInstructionNo());
//            sappostErrorRecordDO.setMaterialsDes(detailDO.getMaterialName());
//            sappostErrorRecordService.add(sappostErrorRecordDO);
//            throw new Exception("过账失败，返回码" + map.get(RETURN_CODE) + "," + map.get(RETURN_MESSAGE));
//        }
//        //过账成功，删除过账失败记录
//        sappostErrorRecordService.updateInsDel(detailDO.getDeliveryInstructionNo(), detailDO.getOrgId(), detailDO.getMaterialNo(), detailDO.getRowNo());
//
//        detailDO.setPostingState(detailDO.getAmount().compareTo(detailDO.getRealAmount()) > 0 ? PostingStatusEnum.PART_POSTING.getStatusCode() : PostingStatusEnum.ALL_POSTING.getStatusCode());
//        // 记录过账信息
//
//        DeliveryInstructionPostingDO postingDO = fillPostingInfo(detailId, map, postQty, userId);
//        deliveryInstructionPostingMapper.insert(postingDO);
//
//        boolean success = deliveryInstructionDetailMapper.updateByPrimaryKeySelective(detailDO) > 0;
//        if (success) {
//            updateDeliveryInstruct(deliveryInstructionDO);
//        }
//        return ErrorCode.Success;
//    }


    /**
     * 判断并更新主表过账状态
     *
     * @param deliveryInstructionDO
     * @throws Exception
     */
    private void updateDeliveryInstruct(DeliveryInstructionDO deliveryInstructionDO) {
        int num = deliveryInstructionDetailMapper.countNotPosted(deliveryInstructionDO.getDeliveryOrder(), deliveryInstructionDO.getOrgId());
        DeliveryInstructionDO deliveryInstruction = new DeliveryInstructionDO();
        deliveryInstruction.setId(deliveryInstructionDO.getId());
        deliveryInstruction.setPostingState(num > 0 ? PostingStatusEnum.PART_POSTING.getStatusCode() : PostingStatusEnum.ALL_POSTING.getStatusCode());
        deliveryInstructionMapper.updateByPrimaryKeySelective(deliveryInstructionDO);
    }

    /**
     * 代理原来的过账方法doPosting，将过账返回的错误信息更新到sapErrorMsg中，抛出异常不回滚
     *
     * @param
     * @param
     * @return
     */
//    public ErrorCode posting(String detailId, String userId) throws Exception {
//        ErrorCode code = null;
//        try {
//            code = doPosting(detailId, userId);
//            updateSapErrorMsg(detailId, StringUtils.EMPTY);
//        } catch (Exception e) {
//            updateSapErrorMsg(detailId, e.getMessage());
//            throw new Exception(e.getMessage());
//        }
//        return code;
//    }

//    @Async
//    public void postingBatch(List<DeliveryInstructionDetailDO> details, String sapCode){
//        LogHelper.monitor("=======配送指令过账多线程执行开始，当前企业："+sapCode+"，当前处理集合数量："+details.size()+"=======");
//        List<String> errorIds = new ArrayList<>();
//        for(DeliveryInstructionDetailDO detailDO : details){
//            try {
//                ErrorCode errorCode = posting(detailDO.getId(), "system");
//                if (!ErrorCode.Success.equals(errorCode)) {
//                    errorIds.add(detailDO.getId());
//                }
//            } catch (Exception e) {
//                LogHelper.error(detailDO.getId()+"|"+e.getMessage().toString(),ErrorCode.Failure.getCode());
//                errorIds.add(detailDO.getId());
//            }
//        }
//        addErrorLog("过账失败的配送指令入库单详情ID:", errorIds);
//        LogHelper.monitor("=======配送指令过账多线程执行结束，当前企业："+sapCode+"，当前处理集合数量："+details.size()+"，执行失败数："+errorIds.size()+"=======");
//    }
    private void addErrorLog(String logTypeDesc, List<String> errorIds) {
        if (CollectionUtils.isNotEmpty(errorIds)) {
            LogHelper.monitor(logTypeDesc + errorIds.toString());
        }
    }

    /**
     * 更新sap过账错误信息字段
     *
     * @param detailId
     * @param errorMsg
     */
    private void updateSapErrorMsg(String detailId, String errorMsg) {
        DeliveryInstructionDetailDO detailDO = new DeliveryInstructionDetailDO();
        detailDO.setId(detailId);
        detailDO.setSapErrorMsg(errorMsg);
        deliveryInstructionDetailMapper.updateByPrimaryKeySelective(detailDO);
    }

    /**
     * 过账信息
     *
     * @param detailId
     * @param map
     * @param postQty
     * @param userId
     * @return
     */
    private DeliveryInstructionPostingDO fillPostingInfo(String detailId,Map<String, String> map, BigDecimal postQty, String userId) {
        DeliveryInstructionPostingDO postingDO = new DeliveryInstructionPostingDO();
        postingDO.setDetailId(detailId);
        postingDO.setInVoucher(map.get(IN_VOUCHER_CODE));
        postingDO.setOutVoucher(map.get(OUT_VOUCHER_CODE));
        postingDO.setPostingQty(postQty);
        postingDO.setCreateId(userId);
        if("system".equals(userId)){
            postingDO.setCreateName("system");
        }
        else {
            postingDO.setCreateName(commonService.getUserName(userId));
        }
        postingDO.setCreateTime(new Date());
        return postingDO;
    }

    /**
     * @Author: WangKe
     * @Description: 根据主键删除配送指令入库记录
     * @Date: 2018/4/17 0017
     */
    public ErrorCode delete(List<String> ids, String orgId){
        int num = deliveryInstructionMapper.findForDeleteByIds(ids);
        if(num > 0){
            return ErrorCode.AbnormalInDeleteError;
        }
        List<String> orderList = deliveryInstructionMapper.findOrderList(ids);
        boolean success = deliveryInstructionMapper.remove(ids)>0;
        //删除入库详情记录
        if(success && CollectionUtils.isNotEmpty(orderList)){
            deliveryInstructionDetailService.deleteByDeliveryOrderList(orderList, orgId);

            //删除事物单
            warehouseInboundService.removeByBusinessOrders(orderList, orgId);
        }
        return success? ErrorCode.Success: ErrorCode.WarehouseIdError;
    }

    /**
     * @Author: WangKe
     * @Description: 查询配送指令入库记录
     * @Date: 2018/4/17 0017
     */
    public PageCommonVO list(SearchCommonVO<DeliveryInstructionVO> condition) {
        PageCommonVO<DeliveryInstructionVO> pageCommonVO = new PageCommonVO();
        PageHelperPlus.orderBy("create_date desc");
        PageHelperPlus.startPage(condition.getPageNum(), condition.getPageSize());
        List<DeliveryInstructionDO> doList = deliveryInstructionMapper.list(condition.getFilters());
        List<DeliveryInstructionVO> voList = new ArrayList<>();
        for (DeliveryInstructionDO entity : doList) {
            DeliveryInstructionVO model = new DeliveryInstructionVO();
            BeanUtils.copyProperties(entity, model);
            voList.add(model);
        }
        pageCommonVO.setPageInfo(new PageInfo(doList));
        pageCommonVO.setPageInfoList(voList);
        return pageCommonVO;
    }

    public List<DeliveryInstructionDO> list(DeliveryInstructionVO vo){
        return deliveryInstructionMapper.list(vo);
    }

    /**
     * @Author: WangKe
     * @Description: 根据主键查找实体
     * @Date: 2018/4/17 0017
     */
    public DeliveryInstructionItemVO findByPK(String id, String type, String orgId){
        DeliveryInstructionItemVO model = new DeliveryInstructionItemVO();
        DeliveryInstructionDO entity;
        if("id".equals(type)){
            entity = deliveryInstructionMapper.selectByPrimaryKey(id);
        }else{
            entity = deliveryInstructionMapper.selectByDeliveryOrder(id, orgId);
        }
        if(entity == null){
            return null;
        }

        List<DeliveryInstructionDetailDO> doList = deliveryInstructionDetailService.findByDeliveryOrder(entity.getDeliveryOrder(), orgId);

        List<DeliveryInstructionDetailVO> voList = new ArrayList<DeliveryInstructionDetailVO>();
        if(CollectionUtils.isNotEmpty(doList)){
            DeliveryInstructionDetailVO deliveryInstructionDetailVO;
            for(DeliveryInstructionDetailDO m:doList){
                deliveryInstructionDetailVO = new DeliveryInstructionDetailVO();
                // 根据过账状态和错误信息判断sap同步状态
                int sapSynStatus = deliveryInstructionDetailService.getSapSynStatus(m.getPostingState(), m.getSapErrorMsg());
                BeanUtils.copyProperties(m, deliveryInstructionDetailVO);
                deliveryInstructionDetailVO.setSapSynStatus(sapSynStatus);
                String loactionCode = deliveryInstructionDetailVO.getStockLocation();
                if (org.apache.commons.lang.StringUtils.isNotBlank(loactionCode)){
                    deliveryInstructionDetailVO.setLocationDesc(warehouseAreaLocationDOMapper.getLocationDesc(loactionCode));
                }
                voList.add(deliveryInstructionDetailVO);
            }
        }
        DeliveryInstructionVO deliveryInstructionVO = new DeliveryInstructionVO();
        BeanUtils.copyProperties(entity, deliveryInstructionVO);

        model.setHeaderInfo(deliveryInstructionVO);
        model.setDetailList(voList);
        return model;
    }

    /**
     * @Author: WangKe
     * @Description: 导出配送指令入库记录列表
     * @Date: 2018/4/17 0017
     */
    public void export(List<String> ids)throws Exception{
        invokeExport(deliveryInstructionMapper.findByIds(ids));
    }

    /**
     * @Author: WangKe
     * @Description: 导出配送指令入库记录列表
     * @Date: 2018/4/17 0017
     */
    public void exportAll(DeliveryInstructionVO condition)throws Exception{
        Integer count = deliveryInstructionMapper.findCountForExportAll(condition);
        List<DeliveryInstructionDO> dataList = new ArrayList<>();
        int times = count/500+1;
        for(int i=0; i<times; i++){
            PageHelperPlus.startPage(i + 1, 500, "CREATE_DATE DESC");
            dataList.addAll(deliveryInstructionMapper.list(condition));
        }
        invokeExport(dataList);
    }

    /**
     * @Author: WangKe
     * @Description: 导出配送指令入库记录列表
     * @Date: 2018/4/17 0017
     */
    private void invokeExport(List<DeliveryInstructionDO> doList)throws Exception{
        String title = "配送指令入库数据导出";
        String[] rowsName = new String[]{"序号", "入库单号", "配送指令", "仓库", "制单人",
                "制单时间", "订单入库状态", "订单过账状态", "零件编码", "零件名称", "收货零件凭证",
                "发货零件凭证", "行号","入库数量", "实际入库数量", "零件入库状态", "SAP同步状态" ,"SAP同步错误原因", "零件过账状态", "储位", "保管员"};
        List<Object[]>  dataList = new ArrayList<Object[]>();
        Object[] objs;
        for (int i = 0; i < doList.size(); i++) {
            DeliveryInstructionDO exportDO = doList.get(i);
            List<DeliveryInstructionDetailDO> detailList = deliveryInstructionDetailMapper.findByDeliveryOrderForLocationUser(exportDO.getDeliveryOrder(),exportDO.getOrgId());
            if (CollectionUtils.isEmpty(detailList)) {
                detailList.add(new DeliveryInstructionDetailDO());
            }
            for (int j = 0; j < detailList.size(); j++ ) {
                objs = new Object[rowsName.length];
                objs[0] = i + 1;
                objs[1] = exportDO.getDeliveryOrder();
                objs[2] = exportDO.getDeliveryInstructionNo();
                objs[3] = exportDO.getWarehouseCode();
                objs[4] = exportDO.getCreateName();
                objs[5] = DateUtil.formatDateTime(exportDO.getCreateDate());
                objs[6] = InboundStatusEnum.getDescByStatus(exportDO.getState());
                objs[7] = PostingStatusEnum.getDescByCode(exportDO.getPostingState());
                DeliveryInstructionDetailDO detail = detailList.get(j);
                if(detail.getMaterialNo()!=null||detail.getMaterialName()!=null){
                    objs[8] = detail.getMaterialNo();
                    objs[9] = detail.getMaterialName();
                    objs[10] = detail.getInVoucher();
                    objs[11] = detail.getOutVoucher();
                    objs[12] = detail.getRowNo();
                    objs[13] = detail.getAmount();
                    objs[14] = detail.getRealAmount();
                    objs[15] = InboundStatusEnum.getDescByStatus(detail.getState());
                    objs[16] = SapSynStatusEnum.getDescByStatus(deliveryInstructionDetailService.getSapSynStatus(detail.getPostingState(), detail.getSapErrorMsg()));
                    objs[17] = detail.getSapErrorMsg();
                    objs[18] = PostingStatusEnum.getDescByCode(detail.getPostingState());
                    objs[19] = detail.getStockLocation();
                    objs[20] = detail.getStockUserName();
                }
                dataList.add(objs);
            }
        }
        ExportUtil exportUtil = new ExportUtil(title, rowsName, dataList);
        exportUtil.export(response);
    }

    /**
     * 手动完成单据<br>
     *     materialsNo 不为null,则更改该单据下的零件状态为“手动完成”状态；如果materialsNo为空，则更改整个单据为“手动完成”状态
     * @param billNo  String 单据编号
     * @param materialsNo String 零件编号
     * @param orgId String 企业ID
     * @return ErrorCode 返回码
     */
    @Transactional(rollbackFor = Exception.class)
    public ErrorCode manualFinish(String billNo,String materialsNo,Integer rowNo,String orgId)throws Exception
    {
        if (StringUtil.isNullOrEmpty(materialsNo))//零件编码为空，更新单据状态为“手动完成”
        {
            deliveryInstructionMapper.updateStatus(3,billNo);
            warehouseInboundService.updateState(billNo,3,orgId);

            deliveryInstructionDetailMapper.updateStatus("3",billNo,null, null);
            warehouseInboundDetailMapper.updateAllStatus(3, billNo, orgId);
        }
        else
        {
            deliveryInstructionDetailMapper.updateStatus("3",billNo,materialsNo, rowNo);
            warehouseInboundService.updateDetailStateRowNo(billNo,materialsNo,null,3,rowNo,orgId);
            ErrorCode errorCode = checkBillFinished(billNo,orgId);

            if(ErrorCode.Success!=errorCode)
            {
                return errorCode;
            }
        }
        return ErrorCode.Success;
    }

    /**
     * 校验单据是否已完成<br>
     *     判断单据下的所有零件是否已经完成，如果都完成，则更改单据状态为完成
     * @param billNo String
     * @param orgId String
     * @return Boolean
     */
    private ErrorCode checkBillFinished(String billNo,String orgId)throws Exception
    {
        List<DeliveryInstructionDetailDO> detailDOs = deliveryInstructionDetailMapper.findByDeliveryOrder(billNo,orgId);
        boolean manul = false;
        boolean flag = true;
        int status;
        for (DeliveryInstructionDetailDO temp : detailDOs)
        {
            if(temp.getState() == 3){
                manul = true;
            }
            if (2==temp.getState() || 3==temp.getState())
            {
                //完成状态
                continue;
            }
            flag =false;
        }

        if(flag){
            if(manul){
                status = 3;
            }else{
                status = 2;
            }
        }else{
            status = 1;
        }
        deliveryInstructionMapper.updateStatus(status,billNo);
        warehouseInboundService.updateState(billNo,status,orgId);
        return ErrorCode.Success;
    }

    /**
     * @Author: WangKe
     * @Description: 配送指令入库撤回
     * @Date: 2018/9/26 0026
     */
    @Transactional(rollbackFor = Exception.class)
    public ErrorCode revoke(String detailId)throws Exception{
        DeliveryInstructionDetailDO detailDO = deliveryInstructionDetailMapper.selectByPrimaryKey(detailId);
        if (null == detailDO) {
            throw new Exception("参数错误，未查询到该条配送指令入库的零件");
        }
        String orgId = detailDO.getOrgId();
        DeliveryInstructionDO deliveryInstructionDO = deliveryInstructionMapper.selectByDeliveryOrder(detailDO.getDeliveryOrder(), detailDO.getOrgId());
        if (null == deliveryInstructionDO) {
            throw new Exception("参数错误，未查询到配送指令入库信息");
        }
        if (detailDO.getRealAmount().compareTo(BigDecimal.ZERO) == 0) {
            throw new Exception("此零件尚未入库，不能撤回");
        }
        if(detailDO.getState() == 3){
            throw new Exception("此零件已结单，不能撤回");
        }
        // 已过账的数量
        BigDecimal hasPostedQty = getHasPostedQty(detailId);
        // 本次撤销数量
        BigDecimal postQty = detailDO.getRealAmount().subtract(hasPostedQty);
        if(postQty.compareTo(BigDecimal.ZERO) == 0){
            throw new Exception("此零件已过账，不能撤回");
        }

        //更新条码状态
        WarehouseInboundRecordVO model = new WarehouseInboundRecordVO();
        model.setOrgId(orgId);
        model.setRowNo(detailDO.getRowNo());
        model.setBusinessOrder(detailDO.getDeliveryOrder());
        PageHelperPlus.orderBy("create_date asc");
        List<WarehouseInboundRecordDO> recordList = warehouseInboundRecordMapper.list(model);
        if(ListUtil.isNullOrEmpty(recordList)){
            throw new Exception("未找到入库记录");
        }
        boolean success;
        BigDecimal num = BigDecimal.ZERO;
        List<BarcodeManageDO> barcodeList = new ArrayList<>();
        for(WarehouseInboundRecordDO inboundRecordDO : recordList){
            BarcodeManageDO barcodeManageDO = barcodeManageMapper.item(inboundRecordDO.getBarCode(), orgId);
            if(barcodeManageDO == null || !"1".equals(barcodeManageDO.getBarcodeStatus()) || !detailDO.getDeliveryOrder().equals(barcodeManageDO.getBillNo())){
                throw new Exception("此零件已有条码出库，不能撤回");
            }
            num = num.add(inboundRecordDO.getAmount());
            if(num.compareTo(hasPostedQty) > 0){
                barcodeList.add(barcodeManageDO);
            }
        }
        if(ListUtil.isNullOrEmpty(barcodeList)){
            throw new Exception("未找到可撤回记录");
        }
        List<String> strList = new ArrayList<>();
        for(BarcodeManageDO barcode : barcodeList){
            barcode.setBarcodeStatus("0");
            barcode.setStatusDesc("已打印");
            success = barcodeManageMapper.update(barcode)>0;
            if(!success){
                throw new Exception("更新条码状态失败");
            }
            strList.add(barcode.getBarcode());
        }

        //删除已入库记录和库存记录
        success = warehouseInboundRecordMapper.removeByBarcodeList(strList, orgId)>0;
        if(!success){
            throw new Exception("删除已入库记录失败");
        }
        success = warehouseInventoryMapper.removeByBarcodeList(strList, orgId)>0;
        if(!success){
            throw new Exception("删除库存记录失败");
        }

        //更新零件详情入库状态
        if(hasPostedQty.compareTo(BigDecimal.ZERO) == 0){
            detailDO.setState(0);
            detailDO.setPostingState(0);
        }else{
            detailDO.setState(1);
            detailDO.setPostingState(1);
        }
        detailDO.setRealAmount(hasPostedQty);
        success = deliveryInstructionDetailMapper.updateByPrimaryKeySelective(detailDO)>0;
        if(!success){
            throw new Exception("更新零件详情状态失败");
        }

        //更新主表入库状态
        int totalNum = deliveryInstructionDetailMapper.findNum(detailDO.getDeliveryOrder(), orgId);
        int stateNum = deliveryInstructionDetailMapper.findNumByState(detailDO.getDeliveryOrder(), 0, orgId);
        if(totalNum == stateNum){
            deliveryInstructionDO.setState(0);
            deliveryInstructionDO.setPostingState(0);
        }else{
            deliveryInstructionDO.setState(1);
            deliveryInstructionDO.setPostingState(1);
        }
        success = deliveryInstructionMapper.updateByPrimaryKeySelective(deliveryInstructionDO)>0;
        if(!success){
            throw new Exception("更新主表状态失败");
        }

        //更新事物表状态
        WarehouseInboundDetailDO inboundDetailDO = warehouseInboundDetailMapper.findByBusinessOrderAndRowNo(detailDO.getDeliveryOrder(), detailDO.getRowNo(), orgId);
        if(inboundDetailDO == null){
            throw new Exception("未找到事务单详情记录");
        }
        inboundDetailDO.setRealAmount(detailDO.getRealAmount());
        inboundDetailDO.setStatus(detailDO.getState());
        success = warehouseInboundDetailMapper.updateByPrimaryKeySelective(inboundDetailDO)>0;
        if(!success){
            throw new Exception("更新事务单详情状态失败");
        }

        WarehouseInboundDO inboundDO = warehouseInboundMapper.selectByOrder(detailDO.getDeliveryOrder(), orgId);
        if(inboundDO == null){
            throw new Exception("未找到事务单主记录");
        }
        inboundDO.setStatus(deliveryInstructionDO.getState());
        success = warehouseInboundMapper.updateByPrimaryKeySelective(inboundDO)>0;
        if(!success){
            throw new Exception("更新事务单主记录状态失败");
        }

        return ErrorCode.Success;
    }
}
